package com.huawang.mdesign.model.service.inter;

import com.huawang.business.command.CommandAddType;
import com.huawang.business.command.CommandParameter;
import com.huawang.business.constants.ErrorCode;
import com.huawang.business.constants.ModelActionName;
import com.huawang.business.constants.ModelConstantURI;
import com.huawang.business.dto.AddModelDTO;
import com.huawang.business.dto.ModelPropertyInfo;
import com.huawang.business.dto.RemoveModelDto;
import com.huawang.business.dto.UpdateModelDTO;
import com.huawang.business.exception.AbortExecutionException;
import com.huawang.business.service.model.base.ElementNameService;
import com.huawang.business.service.model.base.UmlService;
import com.huawang.business.service.model.core.InternalUmlService;
import com.huawang.business.service.model.core.ModelPropertyInfoService;
import com.huawang.business.service.model.core.add.operation.CreateStateMachine;
import com.huawang.business.service.model.core.delete.DeleteService;
import com.huawang.business.service.transaction.TransactionServiceImpl;
import com.huawang.business.util.InstanceVoUtils;
import com.huawang.business.vo.ModelResultVo;
import com.huawang.core.definition.mof.UMLDefinitionConstants;
import com.huawang.core.definition.mof.cmof.reflection.impl.BasicRElement;
import com.huawang.core.definition.mof.instances.MetaClassInstance;
import com.huawang.core.semantics.entity.queryResult.MofResultContainer;
import com.huawang.core.semantics.entity.queryResult.QueryPropertyForm;
import com.huawang.core.semantics.entity.transaction.LocalTransaction;
import com.huawang.core.semantics.exception.CommandException;
import com.huawang.core.semantics.exception.LocalTransactionNotStartException;
import com.huawang.core.semantics.exception.TransactionNotExistingException;
import com.huawang.mdesign.model.service.dto.*;
import com.huawang.mdesign.model.service.util.LogUtil;
import com.huawang.mdesign.model.service.vo.StateInvariantPopupVo;
import com.huawang.mdesign.model.service.facade.dto.LayerOverlayPropertyInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.huawang.business.constants.ModelActionName.ADD_MODEL;

/**
 * @Description 序列图Service
 * @Date 2022/5/18
 * @Author baibf
 */
@Slf4j
@Service
@Primary
public class SequenceService {

    @Autowired
    private UmlService umlService;

    @Autowired
    private InternalUmlService internalUmlService;

    @Autowired
    private PropertyService propertyService;

    @Autowired
    private CreateStateMachine createStateMachine;

    @Autowired
    private DeleteService deleteService;

    @Autowired
    private TransactionServiceImpl transactionService;

    @Autowired
    private ModelPropertyInfoService modelPropertyInfoService;

    @Autowired
    private ElementNameService elementNameService;

    private static final String MESSAGE_OCCURRENCE_SPECIFICATION = "消息发生定义";
    private static final String DESTRUCTION_OCCURRENCE_SPECIFICATION = "破坏发生定义";

    /**
     * @return com.huawang.mdesign.model.service.vo.ModelResultVo
     * @description 拖拽一个Block或property到序列图上，会生成一条生命线。
     * 如果拖的是一个Block，则会创建一个property，将此property设置为Lifeline的represents属性值，并将Block设置为property的type;
     * 如果拖的是一个property，则将此property设置为Lifeline的represents属性值
     * @author baibf
     * @date 2022/5/18
     */
    @NotNull
    public ModelResultVo dragElementToSequenceDiagram(DragElementToSequenceDiagramDTO dragElementToSequenceDiagramDto) {
        LogUtil.printSerializeOnlineLogs("dragElementToSequenceDiagramDto: ", dragElementToSequenceDiagramDto);
        final String projectId = dragElementToSequenceDiagramDto.getProjectId();
        final ModelResultVo modelResultVo = new ModelResultVo();
        MetaClassInstance elementInstance = internalUmlService.fetchInstance(
                dragElementToSequenceDiagramDto.getElementId(), projectId);


        final LocalTransaction transaction = transactionService.createTransaction(dragElementToSequenceDiagramDto.getProjectId(), ADD_MODEL);

        try {
            if (internalUmlService.checkInstanceType(projectId, elementInstance, UMLDefinitionConstants.Property)) {
                CommandParameter lifelineParameter = CommandParameter.builder()
                        .projectId(projectId)
                        .typeId(UMLDefinitionConstants.Lifeline)
                        .type(CommandAddType.MODEL)
                        .parentId(dragElementToSequenceDiagramDto.getParentInstanceId())
                        .instanceId(ModelConstantURI.initInstanceId())
                        .build();
                MetaClassInstance lifelineInstance = umlService.addModel(lifelineParameter);
                umlService.updateModel(projectId, lifelineInstance.getId(), UMLDefinitionConstants.Lifeline_represents,
                        elementInstance);
                modelResultVo.setInstanceId(lifelineInstance.getId());
                // 在交互下创建生命线
            } else if (internalUmlService.checkInstanceType(projectId, elementInstance, UMLDefinitionConstants.Type)) {
                final CommandParameter lifelineParameter = CommandParameter.builder()
                        .projectId(projectId)
                        .typeId(UMLDefinitionConstants.Lifeline)
                        .type(CommandAddType.MODEL)
                        .parentId(dragElementToSequenceDiagramDto.getParentInstanceId())
                        .instanceId(ModelConstantURI.initInstanceId())
                        .build();
                final CommandParameter propertyCommand = CommandParameter.builder()
                        .type(CommandAddType.MODEL)
                        .instanceId(ModelConstantURI.initInstanceId())
                        .parentId(dragElementToSequenceDiagramDto.getParentInstanceId())
                        .projectId(projectId)
                        .typeId(UMLDefinitionConstants.Property)
                        .defaultName("")
                        .build();
                final List<CommandParameter> addModelList = new ArrayList<>();
                addModelList.add(lifelineParameter);
                addModelList.add(propertyCommand);
                final Map<String, MetaClassInstance> addInstancesMap = umlService.addModelByBatch(addModelList)
                        .stream().collect(Collectors.toMap(BasicRElement::getId, it -> it));
                List<UpdateModelDTO> updateModelDTOS = new ArrayList<>();
                updateModelDTOS.add(new UpdateModelDTO(projectId, propertyCommand.getInstanceId(), UMLDefinitionConstants.TypedElement_type,
                        elementInstance));
                updateModelDTOS.add(new UpdateModelDTO(projectId, lifelineParameter.getInstanceId(), UMLDefinitionConstants.Lifeline_represents,
                        addInstancesMap.get(propertyCommand.getInstanceId())));
                umlService.updateModelByBatch(updateModelDTOS);
                modelResultVo.setInstanceId(lifelineParameter.getInstanceId());

            } else {
                log.warn("拖拽模型不是Property或Block!");
            }
            transactionService.commit(dragElementToSequenceDiagramDto.getProjectId());
            InstanceVoUtils.fillModelResultVo(modelResultVo, transaction);
        } catch (TransactionNotExistingException | LocalTransactionNotStartException e) {
            throw AbortExecutionException.build(ErrorCode.TRANSACTION_ERROR, e);
        } catch (Exception e) {
            transactionService.rollBack(dragElementToSequenceDiagramDto.getProjectId(), transaction);
            throw AbortExecutionException.build(ErrorCode.SERVICE_ERROR, e);
        }
        return modelResultVo;
    }

    /**
     * 创建状态常量时，如果状态常量所放置的生命线存在类型（lifeLine的type是其represents属性值的type），
     * 且类型是一个block，behavior或useCase，此时应该有弹窗；
     * 若类型存在，判断类型下是否有状态机（多个），如果存在状态机且状态机的区域（多个）下有状态，找到所有的状态（多个）；
     * 如果类型下有状态机，此方法的返回值内还包含第一个状态机的第一个区域的模型Id。
     *
     * @param projectId  项目id
     * @param instanceId 画布上stateInvariant要放置的模型Id
     * @return com.huawang.mdesign.model.service.vo.StateInvariantPopupVo
     * @author baibf
     * @date 2022/06/10 10:50
     */
    @Nullable
    public StateInvariantPopupVo createStateInvariantPopup(String projectId, String instanceId) {
        LogUtil.printOnlineLogs("projectId: {}, instanceId: {}", projectId, instanceId);
        final MetaClassInstance lifeLine = internalUmlService.fetchInstance(instanceId, projectId);
        if (Objects.isNull(lifeLine)) {
            return null;
        }
        final StateInvariantPopupVo stateInvariantPopupVo = new StateInvariantPopupVo();
        // 获取类型模型
        final MetaClassInstance represents = internalUmlService.queryInstanceProperty(projectId, lifeLine,
                UMLDefinitionConstants.Lifeline_represents);
        if (Objects.isNull(represents)) {
            return null;
        }
        final MetaClassInstance type = internalUmlService.queryInstanceProperty(projectId, represents,
                UMLDefinitionConstants.TypedElement_type);
        if (Objects.isNull(type)) {
            return null;
        }
        if (!internalUmlService.checkInstanceType(projectId, type, UMLDefinitionConstants.SysML_Block)
                && !internalUmlService.checkInstanceType(projectId, type, UMLDefinitionConstants.Behavior)
                && !internalUmlService.checkInstanceType(projectId, type, UMLDefinitionConstants.UseCase)) {
            stateInvariantPopupVo.setPopup(false);
            return stateInvariantPopupVo;
        }
        // 是否弹窗
        stateInvariantPopupVo.setPopup(true);
        // 获取类型模型下所有的状态机
        final List<MetaClassInstance> ownedStateMachines = internalUmlService.queryListInstanceProperty(projectId, type,
                UMLDefinitionConstants.BehavioredClassifier_ownedBehavior).stream().filter(it ->
                internalUmlService.checkInstanceType(projectId, it, UMLDefinitionConstants.StateMachine))
                .collect(Collectors.toList());
        if (CollectionUtils.isEmpty(ownedStateMachines)) {
            return stateInvariantPopupVo;
        }
        // 获取类型模型下的第一个状态机的第一个region
        List<MetaClassInstance> firstStateMachineRegions = internalUmlService.queryListInstanceProperty(projectId,
                ownedStateMachines.get(0), UMLDefinitionConstants.StateMachine_region);
        if (CollectionUtils.isNotEmpty(firstStateMachineRegions)) {
            stateInvariantPopupVo.setCreateStateParentId(firstStateMachineRegions.get(0).getId());
        }

        // 获取类型模型下的所有状态机内的状态
        List<MetaClassInstance> stateList = new ArrayList<>();
        QueryPropertyForm queryPropertyForm = internalUmlService.getQueryPropertyForm(ownedStateMachines,
                Stream.of(UMLDefinitionConstants.NamedElement_name, UMLDefinitionConstants.StateMachine_region
                ).collect(Collectors.toList()));
        MofResultContainer regionContainer = internalUmlService.queryProperty(projectId, queryPropertyForm);
        List<MetaClassInstance> allRegions = regionContainer.getListInstanceMap().values().stream().flatMap(it -> it.values().stream())
                .flatMap(Collection::stream).collect(Collectors.toList());

        QueryPropertyForm subvertexForm = internalUmlService.getQueryPropertyForm(allRegions,
                Stream.of(UMLDefinitionConstants.Region_subvertex, UMLDefinitionConstants.NamedElement_name
                ).collect(Collectors.toList()));
        MofResultContainer subvertexContainer = internalUmlService.queryProperty(projectId, subvertexForm);
        ownedStateMachines.forEach(stateMachine -> {
            List<MetaClassInstance> regions = regionContainer.queryListInstanceProperty(stateMachine.getId(),
                    UMLDefinitionConstants.StateMachine_region);
            regions.forEach(region -> {
                List<MetaClassInstance> subvertexs = subvertexContainer.queryListInstanceProperty(region.getId(),
                        UMLDefinitionConstants.Region_subvertex);
                if (CollectionUtils.isNotEmpty(subvertexs)) {
                    stateList.addAll(subvertexs.stream().filter(it -> internalUmlService.checkInstanceType(
                            projectId, it, UMLDefinitionConstants.State)).collect(Collectors.toList()));
                }
            });
        });

        if (CollectionUtils.isNotEmpty(stateList)) {
            subvertexContainer.addMofPropertyResult(this.internalUmlService.queryProperty(projectId,
                    internalUmlService.getQueryPropertyForm(stateList, UMLDefinitionConstants.NamedElement_name)));
            stateInvariantPopupVo.setSelectElementItems(stateList.stream().map(it ->
                    propertyService.createSelectElementItem(projectId, it,
                            subvertexContainer.queryStringProperty(it.getId(), UMLDefinitionConstants.NamedElement_name)))
                    .collect(Collectors.toList()));
        }
        return stateInvariantPopupVo;

    }

    /**
     * 当在弹窗内点击创建时，如果类型下有状态机，找到第一个状态机的第一个区域（即stateParentId），在其下创建一个状态；
     * 如果类型下没有状态机且类型是状态机，在状态机下创建区域，在区域下创建一个状态；
     * 如果类型不是状态机，在类型下创建状态机，并在状态机的区域下创建一个状态；
     * 当选择一个状态或创建一个状态，会将此状态设置为状态常量的Invariant和State属性值。
     *
     * @param clickCreateStateDto
     * @return com.huawang.mdesign.model.service.vo.ModelResultVo
     * @author baibf
     * @date 2022/06/10 18:04
     */
    @NotNull
    public ModelResultVo clickCreateState(ClickCreateStateDTO clickCreateStateDto) {
        LogUtil.printSerializeOnlineLogs("clickCreateStateDto: ", clickCreateStateDto);
        ModelResultVo modelResultVo = new ModelResultVo();
        final String projectId = clickCreateStateDto.getProjectId();


        LocalTransaction transaction = transactionService.createTransaction(projectId, ADD_MODEL);

        final MetaClassInstance lifeLine = internalUmlService.fetchInstance(clickCreateStateDto.getInstanceId(), projectId);
        MetaClassInstance represents = internalUmlService.queryInstanceProperty(projectId, lifeLine,
                UMLDefinitionConstants.Lifeline_represents);
        if (Objects.isNull(represents)) {
            return modelResultVo;
        }
        MetaClassInstance type = internalUmlService.queryInstanceProperty(projectId, represents,
                UMLDefinitionConstants.TypedElement_type);
        if (Objects.isNull(type)) {
            return modelResultVo;
        }

        try {
            MetaClassInstance state;
            // 画布上状态常量要放置的模型的类型下有状态机且状态机下有区域
            if (StringUtils.isNotEmpty(clickCreateStateDto.getStateParentId())) {
                final CommandParameter parameter = CommandParameter.builder()
                        .projectId(projectId)
                        .parentId(clickCreateStateDto.getStateParentId())
                        .typeId(UMLDefinitionConstants.State)
                        .type(CommandAddType.MODEL)
                        .instanceId(ModelConstantURI.initInstanceId())
                        .build();
                state = umlService.addModel(parameter);
                // 画布上状态常量要放置的模型的类型是状态机
            } else if (internalUmlService.checkInstanceType(projectId, type, UMLDefinitionConstants.StateMachine)) {
                final CommandParameter regionParameter = CommandParameter.builder()
                        .parentId(type.getId())
                        .type(CommandAddType.MODEL)
                        .typeId(UMLDefinitionConstants.Region)
                        .instanceId(ModelConstantURI.initInstanceId())
                        .projectId(projectId)
                        .build();
                MetaClassInstance region = umlService.addModel(regionParameter);
                final CommandParameter stateParameter = CommandParameter.builder()
                        .projectId(projectId)
                        .parentId(region.getId())
                        .typeId(UMLDefinitionConstants.State)
                        .type(CommandAddType.MODEL)
                        .instanceId(ModelConstantURI.initInstanceId())
                        .build();
                state = umlService.addModel(stateParameter);
            } else {
                final AddModelDTO addModelDto = new AddModelDTO();
                addModelDto.setType(CommandAddType.MODEL.getCode());
                addModelDto.setMetaclass(UMLDefinitionConstants.StateMachine);
                addModelDto.setProjectId(projectId);
                addModelDto.setParentId(type.getId());
                // 新建状态机和区域
                MetaClassInstance stateMachine = createStateMachine.doHandler(addModelDto);
                // 为owner设置拥有行为
                createStateMachine.afterHandler(stateMachine, addModelDto);

                final MofResultContainer mofResultContainer = this.internalUmlService.queryProperty(
                        projectId, this.internalUmlService.getQueryPropertyForm(
                                stateMachine, UMLDefinitionConstants.StateMachine_region
                        ));
                final List<MetaClassInstance> regions = mofResultContainer.queryListInstanceProperty(
                        stateMachine.getId(), UMLDefinitionConstants.StateMachine_region);
                if (CollectionUtils.isEmpty(regions)) {
                    throw new CommandException("region 为空");
                }
                final CommandParameter stateParameter = CommandParameter.builder()
                        .projectId(projectId)
                        .parentId(regions.get(0).getId())
                        .typeId(UMLDefinitionConstants.State)
                        .type(CommandAddType.MODEL)
                        .instanceId(ModelConstantURI.initInstanceId())
                        .build();
                state = umlService.addModel(stateParameter);
            }
            transactionService.commit(projectId);
            modelResultVo.setInstanceId(state.getId());
            InstanceVoUtils.fillModelResultVo(modelResultVo, transaction);
        } catch (TransactionNotExistingException | LocalTransactionNotStartException e) {
            throw AbortExecutionException.build(ErrorCode.TRANSACTION_ERROR, e);
        } catch (Exception e) {
            transactionService.rollBack(projectId, transaction);
            throw AbortExecutionException.build(ErrorCode.ADD_MODEL_ERROR, e);
        }

        return modelResultVo;
    }

    /**
     * 创建状态常量，如果状态常量是放在生命线上，需要在状态常量下创建约束；
     * 如果没有传入状态模型，则约束下创建不透明表达式，将约束设置为状态常量的Invariant属性值；
     * 如果传入状态模型，则约束下创建elementValue，将此状态分别设置为元素值的Element属性值，状态常量的Invariant和State属性值;
     *
     * @return com.huawang.mdesign.model.service.vo.ModelResultVo
     * @author baibf
     * @date 2022/06/10 16:11
     */
    @NotNull
    public ModelResultVo createStateInvariant(final CreateStateInvariantDTO createStateInvariantDto) {
        LogUtil.printSerializeOnlineLogs("createStateInvariantDto: ", createStateInvariantDto);
        ModelResultVo modelResultVo = new ModelResultVo();
        final String projectId = createStateInvariantDto.getProjectId();
        final String instanceId = ModelConstantURI.initInstanceId();
        LocalTransaction transaction = transactionService.createTransaction(projectId, ADD_MODEL);

        final MetaClassInstance lifeline = internalUmlService.fetchInstance(createStateInvariantDto.getParentId(), projectId);
        if (Objects.isNull(lifeline)) {
            throw AbortExecutionException.build(ErrorCode.PARAM_ERROR);
        }

        final MetaClassInstance owner = internalUmlService.queryInstanceProperty(projectId,
                lifeline, UMLDefinitionConstants.Element_owner);
        if (Objects.isNull(owner)) {
            throw AbortExecutionException.build(ErrorCode.PARAM_ERROR);
        }
        try {
            final CommandParameter parameter = CommandParameter.builder()
                    .projectId(projectId)
                    .parentId(owner.getId())
                    .typeId(UMLDefinitionConstants.StateInvariant)
                    .type(CommandAddType.MODEL)
                    .instanceId(instanceId)
                    .build();
            final MetaClassInstance stateInvariant = umlService.addModel(parameter);

            umlService.appendModel(projectId, lifeline.getId(), UMLDefinitionConstants.Lifeline_coveredBy,
                    stateInvariant);
            umlService.updateModel(projectId, instanceId, UMLDefinitionConstants.StateInvariant_covered, lifeline);
            if (internalUmlService.checkInstanceType(projectId, lifeline, UMLDefinitionConstants.Lifeline)) {
                final AddModelDTO dto = new AddModelDTO();
                dto.setParentId(instanceId);
                dto.setMetaclass(UMLDefinitionConstants.Constraint);
                dto.setProjectId(projectId);
                dto.setType(CommandAddType.MODEL.getCode());
                MetaClassInstance constraint;

                // 先新建约束填充约束再设置不变量，会导致约束规范丢失
                // 先新建空约束，设置不变量
                constraint = umlService.addModel(dto);
                umlService.updateModel(projectId, stateInvariant.getId(),
                        UMLDefinitionConstants.StateInvariant_invariant, constraint);
                // state存在，填充约束为元素值
                if (StringUtils.isNotEmpty(createStateInvariantDto.getStateId())) {
                    final MetaClassInstance state = internalUmlService.fetchInstance(
                            createStateInvariantDto.getStateId(), projectId);

                    final CommandParameter elementValueParameter = CommandParameter.builder()
                            .typeId(UMLDefinitionConstants.ElementValue)
                            .type(CommandAddType.MODEL)
                            .instanceId(ModelConstantURI.initInstanceId())
                            .projectId(projectId)
                            .parentId(constraint.getId())
                            .build();
                    final MetaClassInstance elementValue = umlService.addModel(elementValueParameter);
                    final List<UpdateModelDTO> updateModelDTOS = new ArrayList<>();
                    updateModelDTOS.add(new UpdateModelDTO(projectId, constraint.getId(),
                            UMLDefinitionConstants.Constraint_specification, elementValue));
                    updateModelDTOS.add(new UpdateModelDTO(projectId, elementValue.getId(),
                            UMLDefinitionConstants.ElementValue_element, state));
                    umlService.updateModelByBatch(updateModelDTOS);
                }

            }
            transactionService.commit(projectId);
            modelResultVo.setInstanceId(stateInvariant.getId());
            InstanceVoUtils.fillModelResultVo(modelResultVo, transaction);
        } catch (TransactionNotExistingException | LocalTransactionNotStartException e) {
            throw AbortExecutionException.build(ErrorCode.TRANSACTION_ERROR, e);
        } catch (Exception e) {
            transactionService.rollBack(projectId, transaction);
            throw AbortExecutionException.build(ErrorCode.ADD_MODEL_ERROR, e);
        }

        return modelResultVo;
    }

    @NotNull
    public ModelResultVo dragElementToLifeLine(DragElementToSequenceDiagramDTO dragElementToSequenceDiagramDto) {
        LogUtil.printSerializeOnlineLogs("dragElementToSequenceDiagramDto: ", dragElementToSequenceDiagramDto);
        final String projectId = dragElementToSequenceDiagramDto.getProjectId();
        final ModelResultVo modelResultVo = new ModelResultVo();

        final Map<String, MetaClassInstance> instanceMap = internalUmlService.fetchInstances(
                Stream.of(dragElementToSequenceDiagramDto.getParentInstanceId(),
                        dragElementToSequenceDiagramDto.getElementId()).collect(Collectors.toList()), projectId);
        final MetaClassInstance parent = instanceMap.get(dragElementToSequenceDiagramDto.getParentInstanceId());
        final MetaClassInstance elementInstance = instanceMap.get(dragElementToSequenceDiagramDto.getElementId());
        if (Objects.isNull(parent) || Objects.isNull(elementInstance)) {
            return modelResultVo;
        }
        if (!internalUmlService.checkInstanceType(projectId, parent, UMLDefinitionConstants.Lifeline)) {
            throw AbortExecutionException.build(ErrorCode.MODEL_CONSTRAINT_ERROR);
        }

        final LocalTransaction transaction = transactionService.createTransaction(projectId, ADD_MODEL);

        final MetaClassInstance represents = internalUmlService.queryInstanceProperty(projectId, parent,
                UMLDefinitionConstants.Lifeline_represents);

        try {
            // property被拖到生命线上，删除生命线的原represents值，再更新属性
            if (internalUmlService.checkInstanceType(projectId, elementInstance, UMLDefinitionConstants.Property)) {
                if (Objects.nonNull(represents)) {
                    deleteService.deleteModel(projectId, represents.getId());
                }
                umlService.updateModel(projectId, parent.getId(), UMLDefinitionConstants.Lifeline_represents,
                        elementInstance);
            }
            // Block被拖到生命线上，更新生命线的represents值的type，如果生命线的represents没有值，则创建property，并设置属性
            if (internalUmlService.checkInstanceType(projectId, elementInstance, UMLDefinitionConstants.Type)) {
                if (Objects.nonNull(represents) && CollectionUtils.isEmpty(represents.getAppliedStereotypes())) {
                    umlService.updateModel(projectId, represents.getId(), UMLDefinitionConstants.TypedElement_type,
                            elementInstance);
                } else {
                    MetaClassInstance interaction = internalUmlService.queryInstanceProperty(projectId, parent,
                            UMLDefinitionConstants.Element_owner);
                    if (interaction != null) {
                        final CommandParameter propertyCommand = CommandParameter.builder()
                                .type(CommandAddType.MODEL)
                                .instanceId(ModelConstantURI.initInstanceId())
                                .parentId(interaction.getId())
                                .projectId(projectId)
                                .typeId(UMLDefinitionConstants.Property)
                                .defaultName("")
                                .build();
                        final MetaClassInstance propertyInstance = umlService.addModel(propertyCommand);
                        final List<UpdateModelDTO> updateModelDTOS = new ArrayList<>();
                        updateModelDTOS.add(new UpdateModelDTO(projectId, propertyInstance.getId(),
                                UMLDefinitionConstants.TypedElement_type, elementInstance));
                        updateModelDTOS.add(new UpdateModelDTO(projectId, parent.getId(),
                                UMLDefinitionConstants.Lifeline_represents, propertyInstance));
                        umlService.updateModelByBatch(updateModelDTOS);
                        modelResultVo.setInstanceId(propertyInstance.getId());
                    }
                }
                // 获取target是此生命线对应的消息，删除消息的signature
                final List<MetaClassInstance> messageOccurrenceSpecifications = internalUmlService.queryListInstanceProperty(projectId, parent,
                        UMLDefinitionConstants.Lifeline_coveredBy).stream().filter(it ->
                        internalUmlService.checkInstanceType(projectId, it,
                                UMLDefinitionConstants.MessageOccurrenceSpecification)).collect(Collectors.toList());

                final Map<String, ModelPropertyInfo> messageModels =
                        modelPropertyInfoService.createModelPropertyInfoMap(projectId,
                                messageOccurrenceSpecifications, Collections.singletonList(UMLDefinitionConstants.MessageEnd_message));
                final List<MetaClassInstance> message = messageModels.values().stream().map(it ->
                        it.queryInstanceValue(UMLDefinitionConstants.MessageEnd_message))
                        .filter(Objects::nonNull).collect(Collectors.toList());
                // 筛选target是此生命线的消息
                final Map<String, ModelPropertyInfo> receiveEventModels = modelPropertyInfoService.createModelPropertyInfoMap(projectId, message,
                        Collections.singletonList(UMLDefinitionConstants.Message_receiveEvent));
                final List<MetaClassInstance> messageList = receiveEventModels.values().stream().map(it ->
                        it.queryInstanceValue(UMLDefinitionConstants.Message_receiveEvent))
                        .filter(Objects::nonNull).collect(Collectors.toList());
                final List<RemoveModelDto> removeModelDtoList = new ArrayList<>();
                messageList.forEach(it ->
                        removeModelDtoList.add(new RemoveModelDto(projectId, it.getId(), UMLDefinitionConstants.Message_signature, null))
                );
                umlService.removeModelByBatch(projectId, removeModelDtoList);
            }
            transactionService.commit(dragElementToSequenceDiagramDto.getProjectId());
            InstanceVoUtils.fillModelResultVo(modelResultVo, transaction);
            modelResultVo.getModifyModel().add(parent.getId());
        } catch (TransactionNotExistingException | LocalTransactionNotStartException e) {
            throw AbortExecutionException.build(ErrorCode.TRANSACTION_ERROR, e);
        } catch (Exception e) {
            transactionService.rollBack(dragElementToSequenceDiagramDto.getProjectId(), transaction);
            throw AbortExecutionException.build(ErrorCode.SERVICE_ERROR, e);
        }
        return modelResultVo;
    }

    @NotNull
    public ModelResultVo shapeLayerOverlay(ShapeLayerOverlayDTO shapeLayerOverlayDTO) {
        LogUtil.printSerializeOnlineLogs("shapeLayerOverlayDTO: ", shapeLayerOverlayDTO);
        final String projectId = shapeLayerOverlayDTO.getProjectId();
        String instanceId = shapeLayerOverlayDTO.getInstanceId();
        List<String> coveredInstanceIds = shapeLayerOverlayDTO.getCoveredInstanceIds();
        List<String> exposeInstanceIds = shapeLayerOverlayDTO.getExposeInstanceIds();

        final ModelResultVo modelResultVo = new ModelResultVo();
        LocalTransaction transaction = transactionService.createTransaction(projectId, ModelActionName.UPDATE_PROPERTY);
        try {
            LayerOverlayPropertyInfo layerOverlayPropertyInfo = buildLayerOverlayPropertyOperation(projectId,
                    instanceId, coveredInstanceIds, exposeInstanceIds);
            List<UpdateModelDTO> updateModelDTOS = layerOverlayPropertyInfo.getUpdateModelDTOS();
            Map<String, MetaClassInstance> updateNameMap = layerOverlayPropertyInfo.getUpdateNameMap();
            Map<String, MetaClassInstance> messageOccurrenceSpecificationMap = internalUmlService.fetchInstances(
                    new ArrayList<>(updateNameMap.keySet()), projectId);
            // 批量更新时（操作符放在消息上，操作数的InteractionOperand-fragment属性值顺序有问题）
            QueryPropertyForm queryPropertyForm = internalUmlService.getQueryPropertyForm(new ArrayList<>(messageOccurrenceSpecificationMap.values()),
                    UMLDefinitionConstants.NamedElement_name);
            MofResultContainer messageResult = internalUmlService.queryProperty(projectId, queryPropertyForm);
            if (CollectionUtils.isNotEmpty(updateModelDTOS)) {
                updateModelDTOS.forEach(updateModelDTO -> {
                    String updateInstanceId = updateModelDTO.getInstanceId();
                    MetaClassInstance parent = updateNameMap.get(updateInstanceId);
                    if (Objects.nonNull(parent)) {
                        MetaClassInstance messageOccurrenceSpecification = messageOccurrenceSpecificationMap.get(updateInstanceId);
                        String name = messageResult.queryStringProperty(updateInstanceId, UMLDefinitionConstants.NamedElement_name);
                        if (StringUtils.isNotEmpty(name) && name.contains(MESSAGE_OCCURRENCE_SPECIFICATION)) {
                            name = MESSAGE_OCCURRENCE_SPECIFICATION;
                        } else if (StringUtils.isNotEmpty(name) && name.contains(DESTRUCTION_OCCURRENCE_SPECIFICATION)) {
                            name = DESTRUCTION_OCCURRENCE_SPECIFICATION;
                        } else {
                            log.info("不重置name");
                        }

                        final String newName = elementNameService.fetchDefaultName(projectId, name, parent, messageOccurrenceSpecification);
                        umlService.updateModel(projectId, updateInstanceId, UMLDefinitionConstants.NamedElement_name, newName);
                    }

                    umlService.updateModel(projectId, updateInstanceId, updateModelDTO.getPropertyId(), updateModelDTO.getValue());
                });
            }
            transactionService.commit(projectId);
            modelResultVo.setInstanceId(shapeLayerOverlayDTO.getInstanceId());
            InstanceVoUtils.fillModelResultVo(modelResultVo, transaction);
        } catch (TransactionNotExistingException | LocalTransactionNotStartException e) {
            throw AbortExecutionException.build(ErrorCode.TRANSACTION_ERROR, e);
        } catch (Exception e) {
            transactionService.rollBack(projectId, transaction);
            throw AbortExecutionException.build(ErrorCode.PROPERTY_UPDATE_ERROR, e);
        }
        return modelResultVo;
    }

    @NotNull
    private LayerOverlayPropertyInfo buildLayerOverlayPropertyOperation(String projectId, String instanceId,
                                                                        List<String> coveredInstanceIds,
                                                                        List<String> exposeInstanceIds) {
        LogUtil.printOnlineLogs("projectId: {}, instanceId: {}, coveredInstanceIds: {}, exposeInstanceIds: {}",
                projectId, instanceId, coveredInstanceIds, exposeInstanceIds);
        List<String> instanceIds = new ArrayList<>(coveredInstanceIds);
        instanceIds.add(instanceId);
        if (CollectionUtils.isNotEmpty(exposeInstanceIds)) {
            instanceIds.addAll(exposeInstanceIds);
        }
        Map<String, MetaClassInstance> instanceMap = internalUmlService.fetchInstances(instanceIds, projectId);
        MetaClassInstance instance = instanceMap.get(instanceId);
        if (Objects.isNull(instance)) {
            throw AbortExecutionException.build(ErrorCode.MODEL_NO_EXIST);
        }
        List<MetaClassInstance> instances = instanceIds.stream().map(instanceMap::get).filter(Objects::nonNull).collect(Collectors.toList());
        Map<String, Set<String>> givenTypes = internalUmlService.getGivenTypes(projectId, instances);


        List<UpdateModelDTO> updateModelDTOS = new ArrayList<>();
        Map<String, MetaClassInstance> updateNameMap = new HashMap<>();
        // 图层中上一层的是消息
        if (internalUmlService.checkInstanceType(projectId, instance, UMLDefinitionConstants.Message)) {
            final Optional<String> coveredOperandInstanceIdOptional = coveredInstanceIds.stream().filter(StringUtils::isNotBlank).findAny();
            QueryPropertyForm queryPropertyForm = internalUmlService.getQueryPropertyForm(instance,
                    Stream.of(UMLDefinitionConstants.Message_sendEvent,
                            UMLDefinitionConstants.Message_receiveEvent).collect(Collectors.toList()));
            MofResultContainer messageResult = internalUmlService.queryProperty(projectId, queryPropertyForm);
            List<MetaClassInstance> events = new ArrayList<>();
            events.add(messageResult.queryInstanceProperty(instanceId,
                    UMLDefinitionConstants.Message_sendEvent));
            events.add(messageResult.queryInstanceProperty(instanceId,
                    UMLDefinitionConstants.Message_receiveEvent));
            // 消息移进的是组合片段
            final List<MetaClassInstance> messageOccurrenceSpecifications = events.stream().filter(it -> internalUmlService.checkInstanceType(projectId, it,
                    UMLDefinitionConstants.MessageOccurrenceSpecification)).collect(Collectors.toList());
            if (coveredOperandInstanceIdOptional.isPresent()) {
                messageOccurrenceSpecifications.forEach(messageOccurrenceSpecification -> {
                    updateModelDTOS.add(new UpdateModelDTO(projectId, messageOccurrenceSpecification.getId(),
                            UMLDefinitionConstants.InteractionFragment_enclosingOperand,
                            instanceMap.get(coveredOperandInstanceIdOptional.get())));
                    updateNameMap.put(messageOccurrenceSpecification.getId(),
                            instanceMap.get(coveredOperandInstanceIdOptional.get()));
                });
                // 消息移进的是整个交互
            } else {
                MetaClassInstance interaction = internalUmlService.fetchInstance(instance.getOwnerId(), projectId);
                messageOccurrenceSpecifications.forEach(messageOccurrenceSpecification ->
                    updateModelDTOS.add(new UpdateModelDTO(projectId, messageOccurrenceSpecification.getId(),
                            UMLDefinitionConstants.InteractionFragment_enclosingInteraction, interaction))
                );

            }
        }
        // 图层中上一层的是操作数
        if (internalUmlService.checkInstanceType(projectId, instance, UMLDefinitionConstants.InteractionOperand)) {
            final List<MetaClassInstance> messageOccurrenceSpecifications = getMessageOccurrenceSpecifications(projectId,
                    coveredInstanceIds, givenTypes, instanceMap);
            messageOccurrenceSpecifications.forEach(messageOccurrenceSpecification -> {
                updateModelDTOS.add(new UpdateModelDTO(projectId, messageOccurrenceSpecification.getId(),
                        UMLDefinitionConstants.InteractionFragment_enclosingOperand, instance));
                updateNameMap.put(messageOccurrenceSpecification.getId(), instance);

            });
            if (CollectionUtils.isNotEmpty(exposeInstanceIds)) {
                final List<MetaClassInstance> outsideMessageOccurrenceSpecifications = getMessageOccurrenceSpecifications(
                        projectId, exposeInstanceIds, givenTypes, instanceMap);
                final MetaClassInstance loop = internalUmlService.fetchInstance(instance.getOwnerId(), projectId);
                final MetaClassInstance loopOwner = internalUmlService.queryInstanceProperty(projectId, loop,
                        UMLDefinitionConstants.Element_owner);
                String propertyKey = UMLDefinitionConstants.InteractionFragment_enclosingInteraction;
                if (internalUmlService.checkInstanceType(projectId, loopOwner,
                        UMLDefinitionConstants.InteractionOperand)) {
                    propertyKey = UMLDefinitionConstants.InteractionFragment_enclosingOperand;
                }
                for (MetaClassInstance messageOccurrenceSpecification : outsideMessageOccurrenceSpecifications) {
                    updateModelDTOS.add(new UpdateModelDTO(projectId, messageOccurrenceSpecification.getId(), propertyKey, loopOwner));
                    updateNameMap.put(messageOccurrenceSpecification.getId(), loopOwner);
                }
            }
        }
        LayerOverlayPropertyInfo layerOverlayPropertyInfo = new LayerOverlayPropertyInfo();
        layerOverlayPropertyInfo.setUpdateModelDTOS(updateModelDTOS);
        layerOverlayPropertyInfo.setUpdateNameMap(updateNameMap);
        return layerOverlayPropertyInfo;
    }


    private List<MetaClassInstance> getMessageOccurrenceSpecifications(String projectId,
                                                                       List<String> instanceIds,
                                                                       Map<String, Set<String>> givenTypes,
                                                                       Map<String, MetaClassInstance> instanceMap) {
        LogUtil.printOnlineLogs("projectId: {}, instanceIds: {}", projectId, instanceIds);
        List<MetaClassInstance> messages = new ArrayList<>();
        List<MetaClassInstance> events = new ArrayList<>();
        instanceIds.forEach(coveredInstanceId -> {
            if (givenTypes.get(coveredInstanceId).contains(UMLDefinitionConstants.Message)) {
                messages.add(instanceMap.get(coveredInstanceId));
            }
            if (givenTypes.get(coveredInstanceId).contains(UMLDefinitionConstants.MessageOccurrenceSpecification)) {
                events.add(instanceMap.get(coveredInstanceId));
            }
        });
        QueryPropertyForm queryPropertyForm = internalUmlService.getQueryPropertyForm(messages,
                Stream.of(UMLDefinitionConstants.Message_sendEvent,
                        UMLDefinitionConstants.Message_receiveEvent).collect(Collectors.toList()));
        MofResultContainer messageResult = internalUmlService.queryProperty(projectId, queryPropertyForm);
        messages.forEach(message -> {
            events.add(messageResult.queryInstanceProperty(message.getId(),
                    UMLDefinitionConstants.Message_sendEvent));
            events.add(messageResult.queryInstanceProperty(message.getId(),
                    UMLDefinitionConstants.Message_receiveEvent));
        });
        return events.stream().filter(it -> internalUmlService.checkInstanceType(projectId, it,
                UMLDefinitionConstants.MessageOccurrenceSpecification)).collect(Collectors.toList());
    }


    public ModelResultVo messageEndChange(MessageEndChangeDTO messageEndChangeDTO) {
        final String projectId = messageEndChangeDTO.getProjectId();
        final List<MessageEndChangeInfo> messageEndChangeInfos = messageEndChangeDTO.getMessageEndChangeInfos();
        final Map<String, String> messageEndChangeInfoMap = messageEndChangeInfos.stream()
                .collect(Collectors.toMap(MessageEndChangeInfo::getMessageId, MessageEndChangeInfo::getAimInstanceId, (k, v) -> k));
        List<String> instanceIds = new ArrayList<>();
        final Set<String> messageIds = messageEndChangeInfoMap.keySet();
        instanceIds.addAll(messageIds);
        instanceIds.addAll(messageEndChangeInfoMap.values());
        final Map<String, MetaClassInstance> instanceMap = internalUmlService.fetchInstances(instanceIds, projectId);

        final List<MetaClassInstance> messageList = messageIds.stream().map(instanceMap::get).collect(Collectors.toList());
        QueryPropertyForm queryPropertyForm = internalUmlService.getQueryPropertyForm(messageList,
                Stream.of(UMLDefinitionConstants.Message_sendEvent,
                        UMLDefinitionConstants.Message_receiveEvent).collect(Collectors.toList()));
        MofResultContainer messageResult = internalUmlService.queryProperty(projectId, queryPropertyForm);
        List<MetaClassInstance> events = new ArrayList<>();
        messageIds.forEach(messageId -> {
            events.add(messageResult.queryInstanceProperty(messageId, UMLDefinitionConstants.Message_sendEvent));
            events.add(messageResult.queryInstanceProperty(messageId, UMLDefinitionConstants.Message_receiveEvent));
        });
        queryPropertyForm.add(events, UMLDefinitionConstants.NamedElement_name);
        messageResult.addMofPropertyResult(internalUmlService.queryProperty(projectId,
                internalUmlService.getQueryPropertyForm(events, UMLDefinitionConstants.NamedElement_name)));

        final ModelResultVo modelResultVo = new ModelResultVo();
        LocalTransaction transaction = transactionService.createTransaction(projectId, ModelActionName.UPDATE_PROPERTY);
        try {

            messageEndChangeInfoMap.forEach((key, value) -> {
                final MetaClassInstance aimInstance = instanceMap.get(value);
                final MetaClassInstance sendEvent = messageResult.queryInstanceProperty(key, UMLDefinitionConstants.Message_sendEvent);
                if (internalUmlService.checkInstanceType(projectId, sendEvent, UMLDefinitionConstants.MessageOccurrenceSpecification)) {
                    modifyMessageEnd(projectId, sendEvent, aimInstance, messageResult);
                }
                final MetaClassInstance receiveEvent = messageResult.queryInstanceProperty(key, UMLDefinitionConstants.Message_receiveEvent);
                if (internalUmlService.checkInstanceType(projectId, receiveEvent, UMLDefinitionConstants.MessageOccurrenceSpecification)) {
                    modifyMessageEnd(projectId, receiveEvent, aimInstance, messageResult);
                }

            });
            transactionService.commit(projectId);
            modelResultVo.setInstanceId(messageEndChangeInfos.get(0).getMessageId());
            InstanceVoUtils.fillModelResultVo(modelResultVo, transaction);
        } catch (TransactionNotExistingException | LocalTransactionNotStartException e) {
            throw AbortExecutionException.build(ErrorCode.TRANSACTION_ERROR, e);
        } catch (Exception e) {
            transactionService.rollBack(projectId, transaction);
            throw AbortExecutionException.build(ErrorCode.PROPERTY_UPDATE_ERROR, e);
        }
        return modelResultVo;
    }


    private void modifyMessageEnd(String projectId, MetaClassInstance event, MetaClassInstance aimInstance, MofResultContainer messageResult) {
        String propertyKey = UMLDefinitionConstants.InteractionFragment_enclosingInteraction;
        if (internalUmlService.checkInstanceType(projectId, aimInstance, UMLDefinitionConstants.InteractionOperand)) {
            propertyKey = UMLDefinitionConstants.InteractionFragment_enclosingOperand;
        }
        String name = messageResult.queryStringProperty(event.getId(), UMLDefinitionConstants.NamedElement_name);
        if (StringUtils.isNotEmpty(name) && name.contains(MESSAGE_OCCURRENCE_SPECIFICATION)) {
            name = MESSAGE_OCCURRENCE_SPECIFICATION;
        } else if (StringUtils.isNotEmpty(name) && name.contains(DESTRUCTION_OCCURRENCE_SPECIFICATION)) {
            name = DESTRUCTION_OCCURRENCE_SPECIFICATION;
        } else {
            log.info("不重置name");
        }

        final String newName = elementNameService.fetchDefaultName(projectId, name, aimInstance, event);
        umlService.updateModel(projectId, event.getId(), UMLDefinitionConstants.NamedElement_name, newName);
        umlService.updateModel(projectId, event.getId(), propertyKey, aimInstance);
    }


    /**
     * 拖拽工具栏的role属性组件生成生命线，并将role属性设置为生命线的represents
     * @param dragDto
     * @return
     */
    @NotNull
    public ModelResultVo dragToolBarLifelineToSequenceDiagram(DragToolBarLifeLineWithRoleDto dragDto) {
        final String projectId = dragDto.getProjectId();
        final ModelResultVo modelResultVo = new ModelResultVo();
        final MetaClassInstance parentInstance = internalUmlService.fetchInstance(dragDto.getParentInstanceId(), projectId);
        final MetaClassInstance parentInstanceOwner = internalUmlService.queryInstanceProperty(projectId, parentInstance, UMLDefinitionConstants.Element_owner);
        // parent的owner不存在
        if (Objects.isNull(parentInstanceOwner)) {
            throw AbortExecutionException.build(ErrorCode.PARAM_ERROR);
        }
        boolean canHaveProperty = internalUmlService.checkInstanceType(projectId, parentInstanceOwner, UMLDefinitionConstants.Class);
        final LocalTransaction transaction = transactionService.createTransaction(projectId, ADD_MODEL);
        MetaClassInstance roleProperty = null;
        try {
            if(canHaveProperty) {
                // 新建role
                final CommandParameter propertyCommand = CommandParameter.builder()
                        .type(CommandAddType.MODEL)
                        .instanceId(ModelConstantURI.initInstanceId())
                        .parentId(parentInstanceOwner.getId())
                        .projectId(projectId)
                        .typeId(UMLDefinitionConstants.Property)
                        .defaultName("")
                        .applyStereotypes(Stream.of(dragDto.getElementId(), UMLDefinitionConstants.Customization_PartProperty).collect(Collectors.toList()))
                        .build();
                roleProperty = umlService.addModel(propertyCommand);
                // 设置role的roleKind
                if (StringUtils.isNotEmpty(dragDto.getRoleKind())) {
                    MetaClassInstance roleKindInstance = internalUmlService.fetchInstance(dragDto.getRoleKind(), projectId);
                    if (Objects.nonNull(roleKindInstance)) {
                        umlService.updateModel(projectId, roleProperty.getId(), UMLDefinitionConstants.UAF_ResourceRole_roleKind, roleKindInstance);
                    }
                }
            }

            // 新建生命线
            CommandParameter lifelineParameter = CommandParameter.builder()
                    .projectId(projectId)
                    .typeId(UMLDefinitionConstants.Lifeline)
                    .type(CommandAddType.MODEL)
                    .parentId(dragDto.getParentInstanceId())
                    .instanceId(ModelConstantURI.initInstanceId())
                    .build();
            MetaClassInstance lifelineInstance = umlService.addModel(lifelineParameter);
            // 更新生命线 represents
            if(roleProperty != null) {
                umlService.updateModel(projectId, lifelineInstance.getId(), UMLDefinitionConstants.Lifeline_represents,
                        roleProperty);
            }

            modelResultVo.setInstanceId(lifelineInstance.getId());
            transactionService.commit(dragDto.getProjectId());
            InstanceVoUtils.fillModelResultVo(modelResultVo, transaction);
        } catch (TransactionNotExistingException | LocalTransactionNotStartException e) {
            throw AbortExecutionException.build(ErrorCode.TRANSACTION_ERROR);
        } catch (Exception e) {
            transactionService.rollBack(dragDto.getProjectId(), transaction);
            throw AbortExecutionException.build(ErrorCode.SERVICE_ERROR, e);
        }
        return modelResultVo;
    }
}
